import os

from clang.cindex import TypeKind, Type, CursorKind, Cursor

from .c_typer import CTypeFinder


def filter_var_name(name: str) -> str:
    # name = name.replace("const ", "")   # const
    return name


def set_unnamed_var_name(declaration: Cursor):
    if not declaration.is_anonymous() or (declaration.is_anonymous() and declaration.kind == CursorKind.FIELD_DECL):
        return declaration.spelling
    p1, p2 = declaration.spelling.split(".h")
    _, line, num = p2.split(":")
    return f"unnamed_{os.path.basename(declaration.location.file.name[:-2])}_{line}_{num[:-1]}_{declaration.hash}"


class CtypeTranslater(CTypeFinder):
    def translate(self, T: Type) -> str:
        # 自定义
        if T.get_declaration().kind != CursorKind.NO_DECL_FOUND:
            return set_unnamed_var_name(T.get_declaration())

        kind = T.kind
        if kind in self.type2ctype:
            return self.type2ctype[kind]
        meth = getattr(self, kind.name, None)
        if meth:
            return filter_var_name(meth(T))
        else:
            raise ValueError(f"{kind.name} Not Found!")

    def CONSTANTARRAY(self, T: Type):
        return "({} * {})".format(self.translate(T.element_type), T.element_count)

    def INCOMPLETEARRAY(self, T: Type):
        return "({} * 0)".format(self.translate(T.element_type))

    def POINTER(self, T: Type):
        pointer = T.get_pointee()
        if pointer.kind in [TypeKind.FUNCTIONPROTO, TypeKind.FUNCTIONNOPROTO]:
            return self.translate(pointer)
        else:
            return "ct.POINTER({})".format(self.translate(pointer))

    def ELABORATED(self, T: Type):
        return self.translate(T.get_canonical())

    def TYPEDEF(self, T: Type):
        return self.translate(T.get_canonical())

    def RECORD(self, T: Type):
        return T.spelling

    def ENUM(self, T: Type):
        return self.translate(T.get_declaration().enum_type)

    def FUNCTIONPROTO(self, T: Type):
        res = "ct.CFUNCTYPE({}, {})".format(self.translate(T.get_result()),
                                          ", ".join([self.translate(arg) for arg in T.argument_types()]))

        return res

    def FUNCTIONNOPROTO(self, T: Type):
        res = "ct.CFUNCTYPE({})".format(self.translate(T.get_result()))

        return res